package org.jeecg.modules.service.wx;

import cn.hutool.extra.pinyin.PinyinUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.jeecg.common.modules.dic.service.IDicConstantsService;
import org.jeecg.common.modules.doctor.entity.Doctor;
import org.jeecg.common.modules.doctor.entity.DoctorWxUserinfoRelation;
import org.jeecg.common.modules.doctor.service.IDoctorService;
import org.jeecg.common.modules.doctor.service.IDoctorWxUserinfoRelationService;
import org.jeecg.common.modules.patient.entity.Patient;
import org.jeecg.common.modules.patient.service.IPatientService;
import org.jeecg.common.modules.wx.entity.WxAccount;
import org.jeecg.common.modules.wx.entity.WxUserinfo;
import org.jeecg.common.modules.wx.service.IWxAccountService;
import org.jeecg.common.modules.wx.service.IWxUserinfoService;
import org.jeecg.common.modules.wx.vo.WxEventReqVo;
import org.jeecg.common.util.ImageUrl;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.WxUtil;
import org.jeecg.common.util.XmlUtil;
import org.jeecg.common.util.enums.StatusEnum;
import org.jeecg.common.util.wx.WxEventTypeEnum;
import org.jeecg.common.util.wx.WxMsgTypeEnum;
import org.jeecg.common.util.wx.WxUrlConvert;
import org.jeecg.modules.config.CustomProperties;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.weixin4j.WeixinException;
import org.weixin4j.model.message.template.TemplateData;
import org.weixin4j.model.sns.SnsUser;
import org.weixin4j.model.user.User;
import org.weixin4j.spring.WeixinTemplate;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import static org.jeecg.common.modules.dic.util.DicConstant.WX_SUB;
import static org.jeecg.common.util.constants.WxConstants.*;

/**
 * @author guoyh
 * @ClassName WeixinService
 * @Description
 * @since 2020/8/23 13:16
 **/
@Service
@Slf4j
public class WeixinService {



    @Resource
    private WeixinTemplate weixinTemplate;

    @Resource
    private IWxAccountService wxAccountService;

    @Resource
    private IWxUserinfoService wxUserinfoService;
    @Resource
    private IPatientService patientService;
    @Resource
    private QrcodeService qrcodeService;
    @Resource
    private IDoctorWxUserinfoRelationService doctorWxUserinfoRelationService;
    @Resource
    private IDicConstantsService dicConstantsService;
    @Resource
    private CustomProperties customProperties;
    @Resource
    private IDoctorService doctorService;
    @Resource
    private RedisUtil redisUtil;

    /**
     * 接收微信事件推送
     *
     * @param xmlStr
     * @param accountId
     * @return
     */
    public String parsingMsg(String xmlStr, String accountId) {
        String respMessage = Strings.EMPTY;
        WxEventReqVo wxEventReqVo = XmlUtil.fromXML(xmlStr, WxEventReqVo.class);
        log.info("微信通知转换后：{}", JSONUtil.toJsonStr(wxEventReqVo));
        if (Objects.isNull(wxEventReqVo)) {
            return REPLAY_ERROR_MESSAGE;
        }
        WxAccount wxAccount = wxAccountService.getByAccountId(accountId);
        if (Objects.isNull(wxAccount) || !Objects.equals(wxAccount.getStatus(), StatusEnum.VALID.getCode())) {
            return respMessage;
        }
        String fromUserName = wxEventReqVo.getFromUserName(); //当前用户的openid
        String msgType = wxEventReqVo.getMsgType();
        WxMsgTypeEnum wxMsgTypeEnum = WxMsgTypeEnum.getByValue(msgType); //消息类型：event
        switch (wxMsgTypeEnum) {
            case EVENT:
                String eventType = wxEventReqVo.getEvent();     //事件类型：SUBSCRIBE：关注；UNSUBSCRIBE：取关；SCAN：已关注公众号的事件，如：扫码
                if (WxEventTypeEnum.SCAN.getValue().equals(eventType) || WxEventTypeEnum.SUBSCRIBE.getValue().equals(eventType)) {
                    //获取患者信息
                    WxUserinfo wxUserinfo = saveOrUpdateWeixinUser(wxAccount,fromUserName);
                    if(WxEventTypeEnum.SUBSCRIBE.getValue().equals(eventType)){  //关注事件
                        String value = dicConstantsService.getByKey(WX_SUB);
                        respMessage = String.format(value, fromUserName,accountId,System.currentTimeMillis());
                    }
                    log.info("扫码事件触发：{}",wxEventReqVo.getEventKey());

                    //wxEventReqVo.getEventKey()：二维码识别时的参数
                    if (StringUtils.isNotBlank(wxEventReqVo.getEventKey())){
                        Patient patient = patientService.getSelfByWxUserinfoId(wxUserinfo.getId()); //本人信息
                        if(wxEventReqVo.getEventKey().startsWith(DOCTOR_QRCODE_PRE) || wxEventReqVo.getEventKey().startsWith(WX_DOCTOR_QRCODE_PRE)) {
                            //新项目扫码
                            qrcodeService.qrcode(wxEventReqVo.getEventKey(), patient, wxUserinfo);
                            log.info("扫医生码处理结束，医生码：{}",wxEventReqVo.getEventKey());
                        }else{
                            //老项目扫码
                            respMessage = FORWARD;
                        }
                    }
                } else if (WxEventTypeEnum.UNSUBSCRIBE.getValue().equals(eventType)) { //取关事件
                    wxUserinfoService.unSub(fromUserName,wxAccount.getId());
                }
                break;
            default:
                break;
        }
        return respMessage;
    }

    /**
     * 更新（初始化）用户信息、初始化患者信息
     * @param wxAccount
     * @param openid
     * @return
     */
    public WxUserinfo saveOrUpdateWeixinUser(WxAccount wxAccount, String openid) {
        try {
            //根据openid获取用户的基本信息
            User user = weixinTemplate.user().info(openid);

            //更新（初始化）用户信息
            WxUserinfo exists = wxUserinfoService.getByOpenid(openid);
            if (Objects.isNull(exists)){
                exists = new WxUserinfo();
            }
            exists = buildWxUserinfo(user,wxAccount.getId(),exists);
            if (Objects.isNull(exists.getId())){
                wxUserinfoService.save(exists);
            }else{
                wxUserinfoService.updateById(exists);
            }

            //初始化患者信息
            initPatientInfo(exists);
            return exists;
        } catch (WeixinException e) {
            log.error("获取微信用户信息失败,openid:{}",e);
            return null;
        }
    }

    /**
     * 初始化患者
     * @param exists
     */
    @Async
    public void initPatientInfo(WxUserinfo exists){
        patientService.getOrCreatePatient(exists);
    }

    public WxUserinfo buildWxUserinfo(User user,String wxAccountId,WxUserinfo wxUserinfo){

        Date now = new Date();
        wxUserinfo.setWxAccountId(wxAccountId);
        wxUserinfo.setOpenid(user.getOpenid());
        wxUserinfo.setUnionid(user.getUnionid());
        wxUserinfo.setNickname(user.getNickname());
        wxUserinfo.setSex(user.getSex());
        wxUserinfo.setCity(user.getCity());
        wxUserinfo.setCountry(user.getCountry());
        wxUserinfo.setProvince(user.getProvince());
        wxUserinfo.setLanguage(user.getLanguage());
        if (StringUtils.isBlank(user.getHeadimgurl())){

            user.setHeadimgurl(ImageUrl.handle(customProperties.getPatientDefaultHeadImg()));
        }
        wxUserinfo.setHeadimgurl(user.getHeadimgurl());
        wxUserinfo.setSubscribeScene(user.getSubscribe_scene());
        wxUserinfo.setQrScene(user.getQr_scene());
        wxUserinfo.setQrSceneStr(user.getQr_scene_str());
        wxUserinfo.setSubscribe(StringUtils.equals(user.getSubscribe(),UN_SUB) ? StatusEnum.INVALID.getCode() : StatusEnum.VALID.getCode());
        if (Objects.isNull(wxUserinfo)){
            wxUserinfo.setCreateTime(now);
            wxUserinfo.setSubscribeTime(now);
        }
        wxUserinfo.setUpdateTime(now);
        wxUserinfo.setLastVisitTime(now);
        if (StringUtils.isNotBlank(user.getNickname())){
//            PinY
            try {
                String pinyin = PinyinUtil.getPinyin(user.getNickname(),"");
                String first = PinyinUtil.getFirstLetter(user.getNickname(),"");
                if (first.length() > 0){
                    first = first.substring(0,1);
                }
                wxUserinfo.setPyinShort(pinyin);
                wxUserinfo.setFirstChar(first);
            } catch (Exception e) {
                log.error("获取拼音失败{}",user.getNickname(),e);
            }
        }
        return wxUserinfo;
    }

    public void getOrCreateWxUserinfo(SnsUser snsUser){
        WxAccount wxAccount = wxAccountService.getByAppid(weixinTemplate.getWeixinConfig().getAppid());
        WxUserinfo wxUserinfo = wxUserinfoService.getByOpenid(snsUser.getOpenid());
        if (Objects.isNull(wxUserinfo)){
            wxUserinfo = new WxUserinfo();
        }
        wxUserinfo.setWxAccountId(wxAccount.getAccountId());
        wxUserinfo.setOpenid(snsUser.getOpenid());
        wxUserinfo.setNickname(snsUser.getNickname());
        wxUserinfo.setSex(snsUser.getSex());
        wxUserinfo.setProvince(snsUser.getProvince());
        wxUserinfo.setCity(snsUser.getCity());
        wxUserinfo.setCountry(snsUser.getCountry());
        wxUserinfo.setHeadimgurl(snsUser.getHeadimgurl());
        wxUserinfo.setUnionid(snsUser.getUnionid());
        if (StringUtils.isNotBlank(snsUser.getNickname())){
            try {
                String pinyin = PinyinUtil.getPinyin(snsUser.getNickname(),"");
                String first = PinyinUtil.getFirstLetter(snsUser.getNickname(),"");
                if (first.length() > 0){
                    first = first.substring(0,1);
                }
                wxUserinfo.setPyinShort(pinyin);
                wxUserinfo.setFirstChar(first);
            } catch (Exception e) {
                log.error("获取拼音失败{}",snsUser.getNickname(),e);
            }
        }
        if (Objects.isNull(wxUserinfo.getId())){
            wxUserinfoService.save(wxUserinfo);
        }else{
            wxUserinfoService.updateById(wxUserinfo);
        }
        initPatientInfo(wxUserinfo);
    }

    /**
     * 发送客服消息
     * @param groupId
     * @param content
     */
    @Async
    public void sendCustomerMessage(String groupId,String content){
        DoctorWxUserinfoRelation relation = doctorWxUserinfoRelationService.getByGroupId(groupId);
        if (Objects.nonNull(relation)){
            Doctor doctor = doctorService.getById(relation.getDoctorId());
            String url = WxUrlConvert.buildChatUrl(customProperties.getH5ApiDomain(),customProperties.getH5Domain(),relation.getImGroupId(),relation.getDoctorId(),weixinTemplate.getAppId());
            try {
                log.info("客服消息，发送url：{}",url);
                String sendContent = String.format(CUSTOMER_TEXT_MESSAGE_TEMPLATE, buildDoctorName(doctor),content,url);  //组织消息内容
                weixinTemplate.message().customSendContent(relation.getOpenid(),sendContent);
            } catch (Exception e) {
                log.warn("发送客服消息失败，openid:【{}】,content：【{}】",relation.getOpenid(),content,e);
                try {
                    List<TemplateData> templateData = WxUtil.buildTemplateData("您有一条新消息",
                            buildDoctorName(doctor),
                            content,
                            LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
                            "点击回复消息");
                    weixinTemplate.message().sendTemplateMessage(relation.getOpenid(),customProperties.getMsgTemplateId(),templateData,url);
                } catch (Exception ex) {
                    log.error("发送模板消息失败，openid:【{}】，content：【{}】",relation.getOpenid(),content,ex);
                }
            }
        }

    }


    private String buildDoctorName(Doctor doctor){
        if (StringUtils.isBlank(doctor.getName())){
            return "医生";
        }
        StringBuffer sb = new StringBuffer(doctor.getName());
        if (StringUtils.isNotBlank(doctor.getTitle())){
            sb.append(doctor.getTitle());
        }
        return sb.toString();
    }



}
